﻿using UnityEngine;
using System.Collections;
using tcom.tools;

/// <summary>
/// 地图辅助工具
/// 1 显示网格
/// 2 编辑格子信息
/// </summary>
public class FACESELECT {

	public static int m_x;		//当前选中的格子横坐标
	public static int m_z;		//当前选中的格子纵坐标
	
	public static float m_fx;		//当前选中的格子横坐标
	public static float m_fz;		//当前选中的格子纵坐标
	
	public static int grdwid = 1;	//格子的宽度
	
	public static int terrwid;		//地形的宽度
	
	public static int terrhei;		//地形的高度
	
	public static Vector3 selPos = new Vector3();
	
	public static float GetGridHei(int x, int z, LayerMask _mask)
	{
		return GetAbsoluteTerrHei(x * grdwid, z * grdwid, _mask);
	}
	
	/// <summary>
	/// 获取地面高度（包括地上物）
	/// 该函数和上面功能相同, 效率待测
	/// </param>
	public static Vector3 GetAbsoluteNormal(float x, float z, LayerMask _mask)
	{
//		RaycastHit hitInfo = new RaycastHit();
		Ray ray = new Ray();
		ray.origin = new Vector3(x, 1000f, z);
		ray.direction = new Vector3(0, -1f, 0);
		
		RaycastHit hit;
		LayerMask n1 = 1 << _mask;
		if(Physics.Raycast(ray, out hit, 1500f, n1))
		{
			return hit.normal;
		}
		else
		{
			return new Vector3(0, 1, 0);
		}
	}
	
	/// <summary>
	/// 获取地面高度（包括地上物）
	/// 该函数和上面功能相同, 效率待测
	/// </param>
	public static float GetAbsoluteTerrHei(float x, float z, LayerMask _mask)
	{
//		RaycastHit hitInfo = new RaycastHit();
		Ray ray = new Ray();
		ray.origin = new Vector3(x, 1000f, z);
		ray.direction = new Vector3(0, -1f, 0);
		
		RaycastHit hit;
		LayerMask n1 = 1 << _mask;
		if(Physics.Raycast(ray, out hit, 1500f, n1))
		{
			float ret = (1000f - hit.distance);
			return ret;
		}
		else
		{
			return 0.0f;
		}
	}
	
	/// <summary>
	/// 获取地面高度（包括地上物）
	/// 该函数和上面功能相同, 效率待测
	/// </param>
	public static float GetAbsoluteTerrHei(float x, float z, LayerMask _mask, out Transform ts)
	{
//		RaycastHit hitInfo = new RaycastHit();
		Ray ray = new Ray();
		ray.origin = new Vector3(x, 1000f, z);
		ray.direction = new Vector3(0, -1f, 0);
		
		RaycastHit hit;
		LayerMask n1 = 1 << _mask;
		if(Physics.Raycast(ray, out hit, 1500f, n1))
		{
			float ret = (1000f - hit.distance);
			ts = hit.transform;
			return ret;
		}
		else
		{
			ts = null;
			return 0.0f;
		}
	}
	
	/// <summary>
	/// 根据绝对坐标, 返回格子信息
	/// </param>
	static Vector3 GetGridedLocation(Vector3 pt)
	{
		float px = pt.x / (float)grdwid;
		float py = pt.y / (float)grdwid;
		float pz = pt.z / (float)grdwid;
		
		return new Vector3(px, py, pz);
	}
	
	/// <summary>
	/// 根据绝对坐标, 返回格子信息
	/// </param>
	static Vector3 GetUnGridedLocation(Vector3 pt)
	{
		return Vector3.Scale(pt, new Vector3(grdwid, grdwid, grdwid));
	}
}

public class TerrainManager : MonoBehaviour
{
	
	static Material lineMaterial = null;
	
	float refhei = 0.1f;
	int boader_left = 50;			
	int boader_right = 50;			
	int boader_bottom = 50;			
	int boader_top = 50;			
	
	public int nBrushSize = 1;
	
	public int viewlen = 10;			//可见范围
	float[] terrainHeights;				//高度图
	
	public int terrwid = 200;			//地图宽度
	public int terrhei = 200;			//地图高度
	
	public bool mbRenderRadar = false;
	public bool m_bShowGrid = false;	//是否显示网格	
	public bool m_bShowWaterGrid = false;
	public bool bTerrOnly = true;
	
	public LayerMask layermask;
	private int _gridsize;
	
	public int gridsize
	{
		get{return _gridsize;}
		set{SetGridSize(value);}
	}
	
	static TerrainManager instance;
	
	public static TerrainManager GetInstance()
	{
		return instance;
	}
	
	void Awake()
	{
		instance = this;
	}
	
	void Start()
	{
		if(GetComponent<Terrain>() != null)
		{
			GetComponent<Terrain>().collider.isTrigger = false;
		}
		
		TEngine.pcallbackgethei = FACESELECT.GetAbsoluteTerrHei;
		SetMapSize(boader_left, boader_bottom, boader_top, boader_right, terrwid, terrhei);
	}
	
	void OnGUI()
	{
		if(m_bShowGrid)
		{
			float refhei = TEngine.GetAbsoluteTerrHei(FACESELECT.m_x, FACESELECT.m_z);
			GUI.Label(new Rect(10, 100, 100, 20), FACESELECT.m_x.ToString() + "_" + FACESELECT.m_z.ToString() + "_" + refhei.ToString());
		}
	}
	
	public Vector3 selpos;
	
	void Update()
	{
		Camera cam = Camera.mainCamera;
		if(cam != null)
		{
			RaycastHit hitInfo = new RaycastHit();
			Ray ray = new Ray();
			ray = cam.ScreenPointToRay(Input.mousePosition);
			
			int layer = LayerMask.NameToLayer("ground");
			layer = 1 << layer;
			if(!Physics.Raycast(ray, out hitInfo, 1500, layer))
			{
				return;
			}
			
			selpos = FACESELECT.selPos - hitInfo.point;
			
			FACESELECT.m_x = (int)(hitInfo.point.x / gridsize);
			FACESELECT.m_z = (int)(hitInfo.point.z / gridsize);
		}
	}
	
	/// <summary>
	/// 设置网格大小
	/// </param>
	void SetGridSize(int _size)
	{
		_gridsize = _size;
	}
	
	/// <summary>
	/// 设置地图大小
	/// b_l 左
	/// b_b 下
	/// b_t 上
	/// b_r 右
	/// </param>
	void SetMapSize(int b_l, int b_b, int b_t, int b_r, int w, int h)
	{
		boader_left = b_l;
		boader_bottom = b_b;
		boader_top = b_t;
		boader_right = b_r;
		
		terrhei = h;
		terrwid = w;
		
		TerrainCollider collider = gameObject.GetComponent<TerrainCollider>();
		if(collider == null)
		{
			Debug.LogError("请为该地形指定 TerrainCollider");
			return;
		}
		
		//根据地图的大小求出格子的大小
		gridsize = (int)(collider.terrainData.size.x / terrwid);
		FACESELECT.grdwid = gridsize;
		FACESELECT.terrwid = terrwid;
		FACESELECT.terrhei = terrhei;
		
		terrainHeights = new float[(terrwid + 1) * (terrhei + 1)];
		
		UpdateHeight();
	}
	
	public void UpdateHeight()
	{
		if(terrainHeights != null)
		{
			for(int i = 0; i < terrwid + 1; i++)
			{
				for(int j = 0; j < terrhei + 1; j++)
				{
					int idx = i * (terrhei + 1) + j;
					if(bTerrOnly)
						terrainHeights[idx] = FACESELECT.GetAbsoluteTerrHei(i * gridsize, j * gridsize, LayerMask.NameToLayer("ground"));
					else
						terrainHeights[idx] = FACESELECT.GetGridHei(i, j, LayerMask.NameToLayer("ground"));
				}
			}
		}
	}
	
	static void CreateLineMaterial()
	{
		if(!lineMaterial)
		{
			lineMaterial = new Material("Shader \"Lines/Colored Blended\" {" +
				"SubShader { Pass { " + 
				" Blend SrcAlpha OneMinusSrcAlpha" + 
				" ZWrite Off Cull Off Fog { Mode Off } " +
				" BindChannels {" +
				" Bind \"Vertex\", vertex Bind \"color\", color }" +
				"} } }");
			
			lineMaterial.hideFlags = HideFlags.HideAndDontSave;
			lineMaterial.shader.hideFlags = HideFlags.HideAndDontSave;
		}
	}
	
	public delegate int TGetBlockValue(int x, int z);
	
	public TGetBlockValue _pGetBlockValue;
	Color GetColor(int i, int j)
	{
		int val = 0;
		if(_pGetBlockValue != null)
			val = _pGetBlockValue(i, j);
		
		if(val == -1)
			return Color.blue;
		
		switch(val)
		{
		case 0: return Color.white;
		case 1: return Color.red;
		case 2: return Color.gray;
		case 3: return Color.green;
		case 4: return Color.yellow;
		case 5: return Color.red;
		case 6: return Color.black;
		case 7: return Color.magenta;
		default: return Color.red;
		}
	}
	
	bool CheckInBoader(int i, int j)
	{
		return false;
		if(i >= boader_left && i < terrwid - boader_right
			&& j >= boader_bottom && j < terrhei - boader_top)
		{
			return false;
		}
		return true;
	}
	
	/// <summary>
	/// 地图区域网格渲染
	/// </param>
	public void OnTDrawGizmosMapArea(Color linecolor)
	{
		if(!m_bShowGrid)
			return;
		
		CreateLineMaterial();
		lineMaterial.SetPass(0);
		GL.Begin(GL.LINES);
		GL.Color(new Color(1, 1, 1, 1));
		
		var camposx = Camera.mainCamera.transform.position.x / gridsize;
		var camposz = Camera.mainCamera.transform.position.z / gridsize;
		
		for(int i = 0; i < terrwid; i++)
		{
			for(int j = 0; j < terrhei; j++)
			{
				if(camposx - i > viewlen || camposx - i < -viewlen) continue;
				if(camposz - j > viewlen || camposz - j < -viewlen) continue;
				
				GL.Color(linecolor);
				
				if(!CheckInBoader(i, j))
				{
					GL.Vertex3(i * gridsize, refhei + GetTerrainHei(i, j), j * gridsize);
					GL.Vertex3(i * gridsize, refhei + GetTerrainHei(i, j + 1), (j + 1) * gridsize);
				}
			}
		}
		
		for(int i = 0; i < terrwid; i++)
		{
			for(int j = 0; j < terrhei; j++)
			{
				if(camposx - i > viewlen || camposx - i < -viewlen) continue;
				if(camposz - j > viewlen || camposz - j < -viewlen) continue;
				
				GL.Color(GetColor(i, j));
				
				if(!CheckInBoader(i, j))
				{
					GL.Vertex3(i * gridsize, refhei + GetTerrainHei(i, j), j * gridsize);
					GL.Vertex3((i + 1) * gridsize, refhei + GetTerrainHei((i + 1), j), j * gridsize);
				}
			}
		}
		
		GL.End();
		
		DrawSetlectState();
	}
	
	void OnTDrawGizmos()
	{
		if(Camera.mainCamera == null)
			return;
		
		if(CamFollow.GetInstance() == null)
			return;
		
		if(CamFollow.GetInstance().target == null)
			return;
		
		if(!m_bShowGrid)
			return;
		
		CreateLineMaterial();
		
		lineMaterial.SetPass(0);
		GL.Begin(GL.LINES);
		GL.Color(new Color(1, 1, 1, 1));
		
		var camposx = CamFollow.GetInstance().target.position.x / gridsize;
		var camposz = CamFollow.GetInstance().target.position.z / gridsize;
		
		for(int i = 0; i < terrwid; i++)
		{
			for(int j = 0; j < terrhei; j++)
			{
				if(camposx - i > viewlen || camposx - i < -viewlen) continue;
				if(camposz - j > viewlen || camposz - j < -viewlen) continue;
				
				GL.Color(GetColor(i, j));
				
				if(!CheckInBoader(i, j))
				{
					GL.Vertex3(i * gridsize, refhei + GetTerrainHei(i, j), j * gridsize);
					GL.Vertex3(i * gridsize, refhei + GetTerrainHei(i, j + 1), (j + 1) * gridsize);
				}
			}
		}
		
		for(int i = 0; i < terrwid; i++)
		{
			for(int j = 0; j < terrhei; j++)
			{
				if(camposx - i > viewlen || camposx - i < -viewlen) continue;
				if(camposz - j > viewlen || camposz - j < -viewlen) continue;
				
				GL.Color(GetColor(i, j));
				
				if(!CheckInBoader(i, j))
				{
					GL.Vertex3(i * gridsize, refhei + GetTerrainHei(i, j), j * gridsize);
					GL.Vertex3((i + 1) * gridsize, refhei + GetTerrainHei((i + 1), j), j * gridsize);
				}
			}
		}
		
		GL.End();
		
		DrawSetlectState();
	}
	
	public float GetTerrainHei(int i, int j)
	{
		if(i < 0 || j < 0 || i > terrwid || j > terrhei)
			return 0;
		
		if(terrainHeights == null)
			return 0;
		
		return terrainHeights[i * (terrhei + 1) + j];
	}
	
	void OnRenderObject()
	{
		OnTDrawGizmos();
	}
	
	/// <summary>
	/// 渲染当前选中状态
	/// </summary>
	void DrawSetlectState()
	{
		int state = 0;
		GL.Begin(GL.LINES);
		if(state >= 0 && state < 4)
		{
			GL.Color(new Color(0, 1, 0, 0.9f));
		}
		else
		{
			GL.End();
			return;
		}
		
		for(int i = -nBrushSize; i < nBrushSize; i++)
		{
			for(int j = -nBrushSize; j < nBrushSize; j++)
			{
				int tempx = FACESELECT.m_x + i;
				int tempz = FACESELECT.m_z + j;
				
				float radius = Mathf.Sqrt(i * i + j * j);
				
				if(radius < nBrushSize)
				{
					GL.Vertex3(tempx * gridsize, refhei + GetTerrainHei(tempx, tempz), tempz * gridsize);
					GL.Vertex3((tempx + 1) * gridsize, refhei + GetTerrainHei(tempx + 1, tempz), tempz * gridsize);
				
					GL.Vertex3((tempx + 1) * gridsize, refhei + GetTerrainHei(tempx + 1, tempz), tempz * gridsize);
					GL.Vertex3((tempx + 1) * gridsize, refhei + GetTerrainHei(tempx + 1, tempz + 1), (tempz + 1) * gridsize);
				
					GL.Vertex3((tempx + 1) * gridsize, refhei + GetTerrainHei(tempx + 1, tempz + 1), (tempz + 1) * gridsize);
					GL.Vertex3(tempx * gridsize, refhei + GetTerrainHei(tempx, tempz + 1), (tempz + 1) * gridsize);
					
					GL.Vertex3(tempx * gridsize, refhei + GetTerrainHei(tempx, tempz + 1), (tempz + 1) * gridsize);
					GL.Vertex3(tempx * gridsize, refhei + GetTerrainHei(tempx, tempz), tempz * gridsize);
				}
			}
		}
		
		GL.End();
	}
}
